package config

import (
	"encoding/json"
	"log"
	"strings"

	"github.com/spf13/viper"
)

type VConfig struct {
	v *viper.Viper
	//opt Options
}

func NewVConfig(opts ...Option) (*VConfig, error) {
	vc := &VConfig{
		v: viper.New(),
		//opt: *newConfigOption(),
	}

	err := vc.init(opts...)
	return vc, err

}

//初始化函数
//先加载defData的内容， 会被环境变量覆盖
//环境变量中的'_'会自动替换为'.'
func (vc *VConfig) init(opts ...Option) error {
	opt := newConfigOption()
	for _, o := range opts {
		o(opt)
	}

	//临时对象，解析默认数据
	if len(opt.defData) > 0 {

		dv := viper.New()
		dv.SetConfigName("config")

		data := string(opt.defData)
		dataType := opt.defDataType

		dv.SetConfigType(dataType)
		if err := dv.ReadConfig(strings.NewReader(data)); nil != err {
			return err
		}

		for _, k := range dv.AllKeys() {
			//log.Println("kv:", k, dv.Get(k))
			vc.v.SetDefault(k, dv.Get(k)) //设置默认值
		}
	}

	//vc.v.SetConfigType(opt.cfgType)

	// 绑定环境变量
	// 设置环境变量前缀
	if opt.envPrefix != "" {
		vc.v.SetEnvPrefix(opt.envPrefix)
	}
	vc.v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
	vc.v.AutomaticEnv()

	// viper.BindEnv("redis.port")

	return nil
}

func (vc *VConfig) ReadConfigFile(opts ...Option) error {

	opt := newConfigOption()
	for _, o := range opts {
		o(opt)
	}

	log.Println("ReadConfigFile :", opt)
	if opt.cfgFile != "" {
		vc.v.SetConfigFile(opt.cfgFile)
		vc.v.SetConfigType(opt.cfgType) // SetConfigFile不会解析文件的后缀，需要设置对应的ConfigType
	} else {
		vc.v.SetConfigName(opt.cfgName)
		vc.v.SetConfigType(opt.cfgType)
		vc.v.AddConfigPath(opt.cfgPath)
	}

	if err := vc.v.ReadInConfig(); nil != err {
		log.Println("ReadInConfig", err)
	}

	return nil
}

func (vc *VConfig) Unmarshal(cfg interface{}) error {
	return vc.v.Unmarshal(cfg)
}

func (vc *VConfig) UnmarshalKey(key string, cfg interface{}) error {
	return vc.v.UnmarshalKey(key, cfg)
}

func (vc *VConfig) WriteConfigAs(file string) error {
	return vc.v.WriteConfigAs(file)
}

// func (vc *VConfig) WriteKeyAs(key string, file string) error {
// 	vv := viper.New()
// 	vv.Set("", vc.v.Get(key))
// 	for _, k := ran
// 	log.Println("====writekeyas", vc.v.Get(key))
// 	for _, k := range vv.AllKeys() {
// 		log.Println("kv:", k, vv.Get(k))

// 	}
// 	return vv.WriteConfigAs(file)
// }

//通过结构体，生成默认文件
func MakeDefFile(cfg interface{}, defFile string) error {
	v := viper.New()

	var defCfg string
	if buf, mErr := json.Marshal(cfg); nil != mErr {
		log.Println("def Marshal Error", mErr)
		return mErr
	} else {
		defCfg = string(buf)
		//log.Println("def string ", defCfg, len(buf), cfg)
	}

	v.SetConfigType("json")
	if err := v.ReadConfig(strings.NewReader(string(defCfg))); nil != err {
		log.Println("ReadConfig Error", err)
		return err
	}

	// log.Println("all settting", v.AllKeys())
	// vv := viper.New()
	// vv.Set("global", v.AllSettings())
	// for _, k := range vv.AllKeys() {
	// 	log.Println("kv:", k, vv.Get(k))
	// 	//viper.SetDefault(k, v.Get(k))

	// }

	if err := v.WriteConfigAs(defFile); nil != err {
		log.Println("save file error", defFile, err)
		return err
	} else {
		log.Println("Save file ok", defFile)
	}

	return nil
}
